package com.yt.order.api.cms;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.yt.common.constant.Result;
import com.yt.common.enums.CodeEnum;
import com.yt.common.utils.StrUtils;
import com.yt.order.common.config.YmlConfig;
import com.yt.order.models.bo.WorkOrderInfoBO;
import com.yt.order.models.bo.WorkOrderInfoSaveBO;
import com.yt.order.models.dto.DispatchRuleConfigDTO;
import com.yt.order.models.dto.DispatchRuleFilterDTO;
import com.yt.order.models.dto.DispatchRuleLogDTO;
import com.yt.order.models.dto.WorkOrderInfoDTO;
import com.yt.order.models.service.*;
import com.yt.order.models.vo.StatisticsVO;
import com.yt.order.models.vo.WorkOrderInfoVO;
import com.yt.product.models.dto.ProductInfoDTO;
import com.yt.product.models.service.IProductInfoService;
import com.yt.user.models.dto.CustomerInfoDTO;
import com.yt.user.models.service.ICustomerInfoService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 系统权限信息控制器
 *
 * @author zhou
 * @Date 2025-09-06 10:41:50
 */

@RestController
@RequestMapping("/cms/workOrderInfo")
@Slf4j
@Api(value = "WorkOrderInfoController", tags = "工单信息接口")
public class WorkOrderInfoController {

    @DubboReference
    private IWorkOrderInfoService workOrderInfoService;
    @DubboReference
    private IProductInfoService productInfoService;
    @DubboReference
    private IDispatchRuleConfigService ruleConfigService;
    @DubboReference
    private IDispatchRuleFilterService ruleFilterService;
    @DubboReference
    private IEmpRatingStatsService empRatingStatsService;
    @DubboReference
    private IEmpAddressService empAddressService;
    @DubboReference
    private IDispatchRuleLogService ruleLogService;
    @Resource
    private YmlConfig ymlConfig;
    @DubboReference
    private IEmpRetreatService empRetreatService;

    @ApiOperation(value = "修改工单信息", notes = "修改工单信息")
    @PostMapping("/update")
    public Result update(WorkOrderInfoSaveBO saveBO) {
        WorkOrderInfoDTO dto = new WorkOrderInfoDTO();
        BeanUtils.copyProperties(saveBO, dto);
        dto.setId(saveBO.getId());
        boolean flag = workOrderInfoService.updateById(dto);
        if (flag) {
            return new Result<>();
        } else {
            return new Result<>(CodeEnum.FAIL_100008);
        }
    }

    @PostMapping("/updateStatus")
    @ApiOperation(value = "修改状态", notes = "修改状态")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "id", required = true, paramType = "query", dataType = "Long")
            , @ApiImplicitParam(name = "status", value = "状态（0待接单 1已接单 2免费）", required = true, paramType = "query", dataType = "Integer")
    })
    public Result updateStatus(Long id, Integer status) {
        WorkOrderInfoDTO dto = new WorkOrderInfoDTO();
        dto.setId(id);
        dto.setStatus(status);
        boolean flag = workOrderInfoService.updateById(dto);
        if (flag) {
            return new Result<>();
        } else {
            return new Result<>(CodeEnum.FAIL_100008);
        }
    }

    @PostMapping("/get")
    @ApiOperation(value = "根据id查找", notes = "根据id查找")
    @ApiImplicitParam(name = "id", value = "id", required = true, paramType = "query", dataType = "Long")
    public Result<WorkOrderInfoDTO> get(@RequestParam("id") Long id) {
        if (id == null) {
            return new Result<>(CodeEnum.FAIL_100002);
        }

        WorkOrderInfoDTO dto = workOrderInfoService.selectById(id);

        return new Result<>(dto);
    }

    @ApiOperation(value = "分页查询工单列表", notes = "支持按状态、时间范围、类型等条件筛选，返回分页数据")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pageNo", value = "页码，从1开始", paramType = "query", dataType = "Integer"),
            @ApiImplicitParam(name = "pageSize", value = "每页条数", paramType = "query", dataType = "Integer"),
            @ApiImplicitParam(name = "status", value = "状态（0待接单 1已接单 2处理中）", paramType = "query", dataType = "Integer"),
            @ApiImplicitParam(name = "type", value = "类型(0客户下单，1自建工单)", paramType = "query", dataType = "Integer"),
            @ApiImplicitParam(name = "startDate", value = "开始时间", paramType = "query", dataType = "Date"),
            @ApiImplicitParam(name = "endDate", value = "结束时间", paramType = "query", dataType = "Date"),
            @ApiImplicitParam(name = "id", value = "工单iD", paramType = "query", dataType = "Long"),
            @ApiImplicitParam(name = "name", value = "客户名称", paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "address", value = "客户地址", paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "priority", value = "优先级(1低，2中，3高)", paramType = "query", dataType = "Integer"),
            @ApiImplicitParam(name = "isEvaluation",value = "是否评论(0未评论1已评论",paramType = "query",dataType = "Integer"),
            @ApiImplicitParam(name = "payStatus", value = "支付状态(0未支付，1支付，2免费)", paramType = "query", dataType = "Integer"),
    })
    @PostMapping("/queryWorkOrderPageList")
    public Result<Page<WorkOrderInfoVO>> queryWorkOrderPageList(WorkOrderInfoBO bo) {
        // 验证分页参数
        if (bo.getPageNo() == null || bo.getPageNo() < 1) {
            bo.setPageNo(1);
        }
        if (bo.getPageSize() == null || bo.getPageSize() < 1 || bo.getPageSize() > 100) {
            bo.setPageSize(10);
        }

        // 构建查询条件
        Wrapper<WorkOrderInfoDTO> wrapper = new EntityWrapper<>();
        //支付状态筛选
        if (bo.getPayStatus() != null) {
            wrapper.eq("pay_status", bo.getPayStatus()); // 假设数据库字段为pay_status
        }
        // 状态筛选
        if (bo.getStatus() != null) {
            wrapper.eq("status", bo.getStatus());
        }

        // 时间范围筛选
        if (bo.getStartDate() != null) {
            wrapper.ge("create_time", bo.getStartDate());
        }
        if (bo.getEndDate() != null) {
            wrapper.le("create_time", bo.getEndDate());
        }

        // 新增类型筛选条件
        if (bo.getType() != null) {
            wrapper.eq("type", bo.getType());
        }

        // 新增工单ID筛选条件（模糊查询）
        if (bo.getId() != null) {
            // 将bigint类型的id转换为字符串后再进行模糊匹配
            wrapper.like("CAST(id AS CHAR)", String.valueOf(bo.getId()));
        }
        // 工单标题筛选条件（模糊查询）
        if (bo.getTitle() != null) {
            wrapper.like("title", bo.getTitle());
        }

        // 客户名称筛选条件（模糊查询）
        if (bo.getName() != null) {
            wrapper.like("name", bo.getName());
        }
        // 客户地址筛选条件（模糊查询）
        if (bo.getAddress() != null) {
            wrapper.like("address", bo.getAddress());
        }
        // 优先级筛选条件
        if (bo.getPriority() != null) {
            wrapper.eq("priority", bo.getPriority());
        }
        //是否评论筛选
        if(bo.getIsEvaluation()!=null){
            wrapper.eq("is_evaluation", bo.getIsEvaluation());
        }
        // 按创建时间倒序排列
        wrapper.orderBy("create_time", false);

        // 执行分页查询
        Page<WorkOrderInfoDTO> dtoPage = new Page<>(bo.getPageNo(), bo.getPageSize());
        dtoPage = workOrderInfoService.selectPage(dtoPage, wrapper);

        // 转换DTO为VO
        Page<WorkOrderInfoVO> voPage = new Page<>();
        BeanUtils.copyProperties(dtoPage, voPage);

        List<WorkOrderInfoVO> voList = dtoPage.getRecords().stream()
                .map(dto -> {
                    WorkOrderInfoVO vo = new WorkOrderInfoVO();
                    BeanUtils.copyProperties(dto, vo);
                    // 处理pic字段：将逗号分隔的字符串转换为列表
                    String picStr = dto.getPic();  // 获取DTO中的pic字符串
                    if (picStr != null && !picStr.isEmpty()) {
                        // 按逗号分割，同时处理可能的空格（如"url1, url2"）
                        List<String> picList = Arrays.stream(picStr.split(","))
                                .map(String::trim)  // 去除每个URL的前后空格
                                .filter(s -> !s.isEmpty())  // 过滤空字符串（避免分割后出现空元素）
                                .collect(Collectors.toList());
                        vo.setPicList(picList);
                    } else {
                        // 如果原字符串为空，设置为空列表（避免null）
                        vo.setPicList(Collections.emptyList());
                    }
                    return vo;
                })
                .collect(Collectors.toList());

        voPage.setRecords(voList);

        return new Result<>(voPage);
    }

    @PostMapping("/updateWorkOrder")
    @ApiOperation(value = "编辑工单", notes = "编辑工单")
    @Transactional
    public Result<WorkOrderInfoDTO> updateWorkOrder(@RequestBody WorkOrderInfoSaveBO SaveBo) {
        if (SaveBo.getId() == null) {
            return new Result<>(CodeEnum.FAIL_100008);
        }
        //0.录入信息
        WorkOrderInfoDTO dto = new WorkOrderInfoDTO();
        BeanUtils.copyProperties(SaveBo, dto);
        //1.查询数据库中原工单数据
        WorkOrderInfoDTO dto2 = workOrderInfoService.selectById(SaveBo.getId());
        if (dto2 == null) {
            return new Result<>(CodeEnum.FAIL_100008);
        }
        if (SaveBo.getProductId() != null) {
            //2.更改产品信息库存
            //2.1根据产品id查询产品信息
            Wrapper<ProductInfoDTO> wrapper = new EntityWrapper<>();
            wrapper.eq("id", SaveBo.getProductId());
            ProductInfoDTO productInfoDTO = productInfoService.selectOne(wrapper);
            if (productInfoDTO == null) {
                return new Result<>(CodeEnum.FAIL_100008);
            }
            //2.2选择产品执行产品信息表库存增减
            if (SaveBo.getProductId() != null) {
                // 计算数量变化：新数量 - 旧数量
                Long quantityChange = SaveBo.getProductQuantity() - dto2.getProductQuantity();
                // 更新库存
                productInfoDTO.setStock(productInfoDTO.getStock() - quantityChange);
                productInfoService.updateById(productInfoDTO);
                //库存不够会报错
                if (productInfoDTO.getStock() < 0) {
                    return new Result<>(CodeEnum.FAIL_100008);
                }
            }
        }
        //3.分配接单员时，状态从未接单更改为处理中
        if (SaveBo.getEmployeeId() != null&&SaveBo.getStatus()==0) {
            dto.setStatus(2);
        }

        workOrderInfoService.updateById(dto);
        return new Result<>(dto);
    }

    @ApiOperation(value = "删除工单信息", notes = "删除工单信息")
    @ApiImplicitParam(name = "id", value = "工单信息id", required = true, paramType = "query", dataType = "Long")
    @PostMapping("/deleteWorkOrder")
    public Result<Boolean> delete(@RequestParam("id") Long id) {
        WorkOrderInfoDTO dto = workOrderInfoService.selectById(id);
        //状态为0时才可以删除
        if (dto.getStatus() == 0) {
            boolean flag = workOrderInfoService.deleteById(id);
            return new Result<>(flag);
        }
        return new Result<>(CodeEnum.FAIL_100009);
    }

    @PostMapping("/addWorkOrder")
    @ApiOperation(value = "自建工单新增", notes = "自建工单新增")
    @Transactional
    public Result<Boolean> workOrderSelfBuiltAdd(@RequestBody WorkOrderInfoSaveBO saveBO) {
        if (saveBO == null) {
            return new Result<>(CodeEnum.FAIL_100002); // 参数为空的错误枚举
        }
        //新增工单
        boolean flag = workOrderInfoService.addOrder(saveBO);
        //有传产品id就修改产品id和产品数量才修改
        //如果选择产品则减少对应产品信息(空就直接返回）
        if (saveBO.getProductId() == null) {
            return new Result<>(flag);
        }
        Wrapper<ProductInfoDTO> wrapper = new EntityWrapper<>();
        wrapper.eq("id", saveBO.getProductId());
        ProductInfoDTO dto = productInfoService.selectOne(wrapper);
        //库存-选择数量
        Long count = dto.getStock() - saveBO.getProductQuantity();
        dto.setStock(count);
        productInfoService.updateById(dto);

        return new Result<>(flag);
    }

    //每日凌晨2点统计一次
    @Scheduled(cron = "0 0 2 * * ?")
    @PostMapping("/statistics")
    @ApiOperation(value = "后台管理统计", notes = "后台管理统计统计")
    public Result<StatisticsVO> Statistics() {
        StatisticsVO statisticsVO = workOrderInfoService.queryStatis();
        return new Result<>(statisticsVO);
    }

    @PostMapping("/appSta")
    @ApiImplicitParam(name = "id", value = "员工or客户id", required = true, paramType = "query", dataType = "Long")
    @ApiOperation(value = "app统计", notes = "app统计")
    public Result<StatisticsVO> appSta(@RequestParam Long id) {
        StatisticsVO statisticsVO = workOrderInfoService.queryAppSta(id);
        return new Result<>(statisticsVO);
    }

    //自动派单
    @PostMapping("/order")
    @ApiOperation(value = "自动派单", notes = "自动派单")
    public Result pandan() {
        //查询待接单的工单列表
        Wrapper<WorkOrderInfoDTO> wrapper = new EntityWrapper<>();
        wrapper.eq("status", 0);
        List<WorkOrderInfoDTO> list = workOrderInfoService.selectList(wrapper);
        if(list==null)
            return new Result<>();
        //对未接单的工单进行派单
        for (WorkOrderInfoDTO workOrderInfoDTO : list) {
            //默认员工id为空
            Long employeeId=null;
            //根据工单id去查询退该工单的员工id
            List<Long> empRetreatId = empRetreatService.queryRet(workOrderInfoDTO.getId());
            //规则日志表
            DispatchRuleLogDTO ruleLogDTO = new DispatchRuleLogDTO();
            //过滤星级员工id列表
            List<Long> starEmployeeId=new ArrayList<>();
            //过滤单量员工id列表
            List<Long> countEmployeeId=new ArrayList<>();
            //过滤距离员工id列表
            List<Long> geoEmployeeId=new ArrayList<>();

            //过滤列表的列表
            List<List<Long>> allEmployeeId=new ArrayList<>();

            //1.选择规则类型
            List<DispatchRuleConfigDTO> ruleConfigDTOList =ruleConfigService.queryRuleConfig(workOrderInfoDTO);
            //如果没有规则，该工单不进行任何操作
            if (ruleConfigDTOList == null) {
                continue;
            }
            //循环规则表
            for (DispatchRuleConfigDTO ruleConfigDTO : ruleConfigDTOList) {
                //2.选择该规则下的过滤条件,按优先级排序过的
                List<DispatchRuleFilterDTO> ruleFilterDTO =ruleFilterService.queryFilter(ruleConfigDTO.getId());
                String des="";
                //循环列表
                for (DispatchRuleFilterDTO filterDTO : ruleFilterDTO) {
                    //运算符
                    String operator = filterDTO.getOperator();
                    //阈值
                    String val=filterDTO.getFilterVal();
                    //过滤详细
                    switch (filterDTO.getFilterType()){
                        //过滤星级
                        case 0:
                            starEmployeeId=empRatingStatsService.queryId(operator,val);
                            allEmployeeId.add(starEmployeeId);
                            des=des+"符合星级过滤的有:"+starEmployeeId.size()+"人";
                            break;
                        //过滤单量
                        case 1:
                            countEmployeeId=workOrderInfoService.queryCountId(operator,val);
                            allEmployeeId.add(countEmployeeId);
                            des=des+"符合单量过滤的有:"+countEmployeeId.size()+"人";
                            break;
                        //过滤地理位置
                        case 2:
                            geoEmployeeId=empAddressService.queryGeoId(workOrderInfoDTO.getAddress(),operator,val);
                            allEmployeeId.add(geoEmployeeId);
                            des=des+"符合地理位置过滤的有:"+geoEmployeeId.size()+"人";
                            break;
                        default:
                            break;
                    }
                    //符合过滤规则条件的员工列表不为空，并且过滤规则是2(or)会执行以下内容
                    if(allEmployeeId!=null && ruleConfigDTO.getMatchMode()==2){
                        //移除退单表的员工id
                        allEmployeeId.remove(empRetreatId);
                        //如果过滤表里面还有员工就结束过滤循环，没有就跳过本次过滤条件执行下一个过滤条件
                        if (allEmployeeId!=null){
                            break;
                        }
                        else{
                            continue;
                        }
                    }
                }

                // 从完整集合开始求交集
                List<Long> finalCandidates = calculateIntersection(allEmployeeId);
                //移除退过该工单的员工id
                finalCandidates.removeAll(empRetreatId);

                //规则日志信息
                ruleLogDTO.setId(ymlConfig.getPkId());
                ruleLogDTO.setOrderId(workOrderInfoDTO.getId());
                ruleLogDTO.setRuleId(ruleConfigDTO.getId());
                ruleLogDTO.setRuleName(ruleConfigDTO.getRuleName());
                ruleLogDTO.setEmpCountFilter(finalCandidates.size());
                ruleLogDTO.setEmpCount(11);
                ruleLogDTO.setFilterDetails(des);
                ruleLogDTO.setExecuteResult("无");
                // 确定最终接单员,确定了接单员就结束规则表的循环
                if (!finalCandidates.isEmpty()) {
                    employeeId = finalCandidates.get(0);
                    ruleLogDTO.setExecuteResult("选择的员工是:"+finalCandidates.get(0));
                    ruleLogService.insert(ruleLogDTO);
                    break;
                }
                ruleLogService.insert(ruleLogDTO);

            }

            //设置接单员
            workOrderInfoDTO.setEmployeeId(employeeId);
            //修改状态为处理中
            if (employeeId != null) {
                workOrderInfoDTO.setStatus(2);
            }
            //更新数据库
            workOrderInfoService.updateById(workOrderInfoDTO);
        }
        return new Result<>();
    }

    // 计算多个列表的交集
    private List<Long> calculateIntersection(List<List<Long>> lists) {
        if (lists.isEmpty()) {
            return new ArrayList<>();
        }

        // 以第一个列表为初始值
        List<Long> result = new ArrayList<>(lists.get(0));

        // 依次与后续列表求交集
        for (int i = 1; i < lists.size(); i++) {
            result.retainAll(lists.get(i));
            // 提前退出：如果中途为空，无需继续计算
            if (result.isEmpty()) {
                return new ArrayList<>();
            }
        }
        return result;
    }
}
